import { Injectable, Inject, InjectionToken, Optional, EventEmitter } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from 'environments/environment';
import {
  IDoc, SwaggerConfig, ITag, IInfo, IPath,
  IDefinition, IPathInfo, IDefinitionData, IDefinitionProperty,
  IParameter
} from '../interfaces';
import { Subscription } from 'rxjs/Subscription';
import { SwaggerTools } from '../tools';

export const SWAGGER_UI_CONFIG = new InjectionToken<SwaggerConfig>('SWAGGER_UI_CONFIG');

@Injectable()
export class SwaggerService {
  loaded: EventEmitter<void> = new EventEmitter<void>();
  error: boolean;
  subscription: Subscription;
  // 原始数据
  original: IDoc;
  tags: ITag[] = [];
  info: IInfo = {};
  paths: IPath = {};
  definitions: IDefinition = {};
  // 格式化数据
  urls: IPathInfo[] = [];

  REF_STR: string = '#/definitions/';

  constructor(
    private http: HttpClient,
    @Optional() @Inject(SWAGGER_UI_CONFIG) private config: SwaggerConfig
  ) {
    this.init();
  }

  /**
   * 从注入的配置中，初始化加载
   * 
   * @memberof SwaggerService
   */
  init(): void {
    if (this.config && this.config.url) {
      this.load(this.config.url);
    }
  }

  /**
   * 从远端加载数据
   * TODO: api_key认证问题
   * 
   * @param {string} url 
   * @memberof SwaggerService
   */
  load(url: string): void {
    this.subscription = this.http.get(url).subscribe(res => {
      this.original = res;
      this.parseOriginal();
      this.loaded.emit();
    }, () => { this.error = true; });
  }

  /**
   * 数据是否加载
   * 
   * @returns {boolean} 
   * @memberof SwaggerService
   */
  isLoaded(): boolean {
    return !!this.original;
  }

  /**
   * 是否数据加载中
   * 
   * @readonly
   * @type {boolean}
   * @memberof SwaggerService
   */
  get loading(): boolean {
    return this.subscription && !this.subscription.closed;
  }

  /**
   * 获取关联数据模型
   * @param ref 
   */
  getRef(ref: string): IDefinitionProperty[] | string[] {
    ref = SwaggerTools.trimRefStr(ref);
    let definition: IDefinitionData = this.definitions[ref];
    if (definition) {
      if (definition.properties) {
        // 设置属性必填
        if (definition.required) {
          for (let p of definition.required) {
            definition.properties[p].required = true;
          }
        }
        return SwaggerTools.toArray(definition.properties);
      } else if (definition.type) {
        if (definition.type === 'object') {
          return this.getRef(definition.additionalProperties.$ref);
        } else if (definition.type === 'string') {
          return ['string'];
        }
      }
    }
    return [ref];
  }

  /**
   * 解析格式源数据
   * 
   * @private
   * @memberof SwaggerService
   */
  private parseOriginal() {
    this.tags = this.original.tags;
    this.info = this.original.info;
    this.paths = this.original.paths;
    this.definitions = this.original.definitions;

    // 格式接口地址
    for (let path in this.paths) {
      let t = this.paths[path];
      for (let method in t) {
        this.urls.push(Object.assign({ url: path, method: method }, t[method]));
      }
    }

    console.log(this.urls);

    // 格式化标签
    for (let tag of this.tags) {
      tag.urls = this.getUrlByTag(tag.name);
    }
    console.log(this.tags);
  }

  /**
   * 根据标签获取接口
   * 
   * @param {string} name 
   * @memberof SwaggerService
   */
  private getUrlByTag(name: string) {
    return this.urls.filter(url => {
      let tags = url.tags.filter(tag => tag.toLowerCase() == name.toLowerCase());
      return tags.length > 0;
    });
  }

}
